package com.analysis.core;

import com.analysis.model.AnalysisResult;
import com.analysis.model.ClassDifference;
import lombok.extern.slf4j.Slf4j;
import org.objectweb.asm.*;
import org.objectweb.asm.tree.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

@Slf4j
@Component
public class JarAnalyzer {
    @Autowired
    private ClassAnalyzer classAnalyzer;

    private static final String CONTROLLER_DESC = "Lorg/springframework/stereotype/Controller;";
    private static final String REST_CONTROLLER_DESC = "Lorg/springframework/web/bind/annotation/RestController;";
    private static final String BOOT_INF_PREFIX = "BOOT-INF.classes.";

    private String normalizeClassName(String className) {
        if (className.startsWith(BOOT_INF_PREFIX)) {
            return className;
        }
        return BOOT_INF_PREFIX + className;
    }

    private String stripBootInfPrefix(String className) {
        if (className.startsWith(BOOT_INF_PREFIX)) {
            return className.substring(BOOT_INF_PREFIX.length());
        }
        return className;
    }

    public AnalysisResult analyze(JarFile oldJar, JarFile newJar) {
        long startTime = System.currentTimeMillis();
        
        Map<String, byte[]> oldClasses = loadClasses(oldJar);
        Map<String, byte[]> newClasses = loadClasses(newJar);
        
        // 分析类的变化
        Map<String, ClassDifference> differences = analyzeClassDifferences(oldClasses, newClasses);
        
        // 分析依赖关系
        analyzeDependencies(differences, oldClasses);
        
        // 分析API影响
        analyzeApiImpact(differences, oldClasses);

        List<ClassDifference> diffList = new ArrayList<>(differences.values());
        
        AnalysisResult result = new AnalysisResult();
        result.setOldJarName(oldJar.getName());
        result.setNewJarName(newJar.getName());
        result.setAnalysisTime(System.currentTimeMillis() - startTime);
        result.setClassDifferences(diffList);
        result.setTotalClasses(oldClasses.size() + newClasses.size());
        result.setModifiedClasses((int)differences.values().stream()
            .filter(diff -> diff.getType() == ClassDifference.DifferenceType.MODIFIED)
            .count());
        result.setAddedClasses((int)differences.values().stream()
            .filter(diff -> diff.getType() == ClassDifference.DifferenceType.ADDED)
            .count());
        result.setDeletedClasses((int)differences.values().stream()
            .filter(diff -> diff.getType() == ClassDifference.DifferenceType.DELETED)
            .count());
        
        log.info("分析完成，发现 {} 个差异", differences.size());
        log.info("新增类: {}, 修改类: {}, 删除类: {}", 
                result.getAddedClasses(), result.getModifiedClasses(), result.getDeletedClasses());
        
        return result;
    }

    private Map<String, byte[]> loadClasses(JarFile jarFile) {
        Map<String, byte[]> classes = new HashMap<>();
        Enumeration<JarEntry> entries = jarFile.entries();
        
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            if (!entry.getName().endsWith(".class")) continue;
            
            try (InputStream is = jarFile.getInputStream(entry)) {
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                byte[] data = new byte[4096];
                int nRead;
                while ((nRead = is.read(data, 0, data.length)) != -1) {
                    buffer.write(data, 0, nRead);
                }
                String className = entry.getName().replace(".class", "").replace('/', '.');
                classes.put(className, buffer.toByteArray());
            } catch (IOException e) {
                log.error("读取类文件失败: " + entry.getName(), e);
            }
        }
        return classes;
    }

    private Map<String, ClassDifference> analyzeClassDifferences(
            Map<String, byte[]> oldClasses,
            Map<String, byte[]> newClasses) {
        Map<String, ClassDifference> differences = new HashMap<>();
        AtomicInteger addedCount = new AtomicInteger();
        AtomicInteger modifiedCount = new AtomicInteger();
        AtomicInteger deletedCount = new AtomicInteger();

        // 检查修改和删除的类
        oldClasses.forEach((className, oldClassBytes) -> {
            byte[] newClassBytes = newClasses.get(className);
            if (newClassBytes == null) {
                // 类被删除
                ClassDifference diff = new ClassDifference();
                diff.setClassName(className);
                diff.setType(ClassDifference.DifferenceType.DELETED);
                differences.put(className, diff);
                deletedCount.incrementAndGet();
                log.info("类被删除: {}", className);
            } else {
                // 比较类的变化
                ClassDifference diff = classAnalyzer.analyzeClass(oldClassBytes, newClassBytes);
                if (diff.getType() != null) {
                    differences.put(className, diff);
                    modifiedCount.incrementAndGet();
                    log.info("类被修改: {}", className);
                }
            }
        });

        // 检查新增的类
        newClasses.forEach((className, newClassBytes) -> {
            if (!oldClasses.containsKey(className)) {
                ClassDifference diff = new ClassDifference();
                diff.setClassName(className);
                diff.setType(ClassDifference.DifferenceType.ADDED);
                differences.put(className, diff);
                addedCount.incrementAndGet();
                log.info("新增类: {}", className);
            }
        });

        log.info("分析完成 - 新增: {}, 修改: {}, 删除: {}", 
                addedCount.get(), modifiedCount.get(), deletedCount.get());
        
        return differences;
    }

    private void analyzeDependencies(
            Map<String, ClassDifference> differences,
            Map<String, byte[]> classes) {
        
        // 分析所有类的依赖关系
        Map<String, Map<String, Set<String>>> methodCallMap = new HashMap<>();
        Map<String, Set<String>> constantUsageMap = new HashMap<>();
        Map<String, Set<String>> apiMethodMap = new HashMap<>(); // 存储API方法信息
        
        // 首先识别所有的API方法
        classes.forEach((className, classBytes) -> {
            try {
                if (isApiClass(classBytes)) {
                    ClassReader reader = new ClassReader(classBytes);
                    ClassNode classNode = new ClassNode();
                    reader.accept(classNode, 0);
                    
                    String normalizedClassName = stripBootInfPrefix(className);
                    @SuppressWarnings("unchecked")
                    List<MethodNode> methods = classNode.methods;
                    for (MethodNode method : methods) {
                        if (method.visibleAnnotations != null) {
                            for (AnnotationNode annotation : method.visibleAnnotations) {
                                if (annotation.desc.contains("Mapping")) {
                                    apiMethodMap.computeIfAbsent(normalizedClassName, k -> new HashSet<>())
                                              .add(method.name + method.desc);
                                    break;
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("分析API类失败: " + className, e);
            }
        });

        // 遍历所有类文件分析依赖
        classes.forEach((className, classBytes) -> {
            try {
                ClassReader reader = new ClassReader(classBytes);
                ClassNode classNode = new ClassNode();
                reader.accept(classNode, 0);
                
                String normalizedClassName = stripBootInfPrefix(className);
                Map<String, Set<String>> methodCalls = new HashMap<>();
                methodCallMap.put(normalizedClassName, methodCalls);
                
                // 检查字段引用
                @SuppressWarnings("unchecked")
                List<FieldNode> fields = classNode.fields;
                for (FieldNode field : fields) {
                    if ((field.access & Opcodes.ACC_STATIC) != 0 && 
                        (field.access & Opcodes.ACC_FINAL) != 0) {
                        // 这是一个常量字段
                        constantUsageMap.putIfAbsent(normalizedClassName, new HashSet<>());
                    }
                }

                // 检查方法中的依赖和方法调用
                @SuppressWarnings("unchecked")
                List<MethodNode> methods = classNode.methods;
                for (MethodNode method : methods) {
                    String methodDesc = method.name + method.desc;
                    Set<String> calledMethods = new HashSet<>();
                    methodCalls.put(methodDesc, calledMethods);
                    
                    // 收集方法调用和常量引用
                    InsnList instructions = method.instructions;
                    for (int i = 0; i < instructions.size(); i++) {
                        AbstractInsnNode insn = instructions.get(i);
                        if (insn instanceof MethodInsnNode) {
                            MethodInsnNode methodInsn = (MethodInsnNode) insn;
                            String targetClass = stripBootInfPrefix(methodInsn.owner.replace('/', '.'));
                            String targetMethod = methodInsn.name + methodInsn.desc;
                            calledMethods.add(targetClass + "." + targetMethod);
                        } else if (insn instanceof FieldInsnNode) {
                            FieldInsnNode fieldInsn = (FieldInsnNode) insn;
                            String targetClass = stripBootInfPrefix(fieldInsn.owner.replace('/', '.'));
                            
                            // 记录常量使用，同时检查是否有BOOT-INF前缀
                            String normalizedTargetClass = normalizeClassName(targetClass);
                            constantUsageMap.computeIfAbsent(targetClass, k -> new HashSet<>())
                                          .add(normalizedClassName);
                            constantUsageMap.computeIfAbsent(normalizedTargetClass, k -> new HashSet<>())
                                          .add(normalizedClassName);
                        }
                    }
                }
            } catch (Exception e) {
                log.error("分析类依赖关系失败: " + className, e);
            }
        });
        
        // 构建API调用链
        Map<String, Set<String>> apiDependencyChain = new HashMap<>();
        Map<String, Set<String>> reverseApiDependencyChain = new HashMap<>();
        
        // 从每个API方法开始构建依赖链
        apiMethodMap.forEach((apiClass, apiMethods) -> {
            Set<String> visited = new HashSet<>();
            buildApiDependencyChain(apiClass, methodCallMap, constantUsageMap, visited, apiDependencyChain, reverseApiDependencyChain);
        });
        
        // 处理所有的差异类
        differences.forEach((className, diff) -> {
            String normalizedClassName = stripBootInfPrefix(className);
            
            // 检查这个类是否在API依赖链中
            if (reverseApiDependencyChain.containsKey(normalizedClassName)) {
                // 获取所有受影响的API类
                Set<String> affectedApiClasses = reverseApiDependencyChain.get(normalizedClassName);
                for (String apiClass : affectedApiClasses) {
                    Set<String> apiMethods = apiMethodMap.get(apiClass);
                    if (apiMethods != null) {
                        for (String apiMethod : apiMethods) {
                            String methodName = apiMethod.substring(0, apiMethod.indexOf('('));
                            String fullApiMethod = apiClass + "." + methodName;
                            // 同时设置 affectedApis 和 dependentApiMethods
                            diff.addAffectedApi(fullApiMethod);
                            diff.addDependentApiMethod(fullApiMethod);
                            log.info("发现API依赖: {} -> {}", fullApiMethod, normalizedClassName);
                        }
                    }
                }
            }
        });
    }
    
    private void buildApiDependencyChain(
            String currentClass,
            Map<String, Map<String, Set<String>>> methodCallMap,
            Map<String, Set<String>> constantUsageMap,
            Set<String> visited,
            Map<String, Set<String>> apiDependencyChain,
            Map<String, Set<String>> reverseApiDependencyChain) {
        
        if (!visited.add(currentClass)) {
            return;
        }
        
        // 检查方法调用依赖
        Map<String, Set<String>> methodCalls = methodCallMap.get(currentClass);
        if (methodCalls != null) {
            for (Set<String> calls : methodCalls.values()) {
                for (String call : calls) {
                    String targetClass = call.substring(0, call.lastIndexOf('.'));
                    // 建立双向依赖关系
                    apiDependencyChain.computeIfAbsent(targetClass, k -> new HashSet<>()).add(currentClass);
                    reverseApiDependencyChain.computeIfAbsent(targetClass, k -> new HashSet<>()).add(currentClass);
                    buildApiDependencyChain(targetClass, methodCallMap, constantUsageMap, visited, 
                                         apiDependencyChain, reverseApiDependencyChain);
                }
            }
        }
        
        // 检查常量使用依赖
        constantUsageMap.forEach((constClass, users) -> {
            String normalizedConstClass = stripBootInfPrefix(constClass);
            if (users.contains(currentClass)) {
                // 建立双向依赖关系
                apiDependencyChain.computeIfAbsent(normalizedConstClass, k -> new HashSet<>()).add(currentClass);
                reverseApiDependencyChain.computeIfAbsent(normalizedConstClass, k -> new HashSet<>()).add(currentClass);
                buildApiDependencyChain(normalizedConstClass, methodCallMap, constantUsageMap, visited, 
                                     apiDependencyChain, reverseApiDependencyChain);
            }
        });
    }

    private void analyzeApiImpact(Map<String, ClassDifference> differences, Map<String, byte[]> classes) {
        // 首先找出所有的API类和方法
        Map<String, Map<String, String>> apiMethodsMap = new HashMap<>();
        
        classes.forEach((className, classBytes) -> {
            String normalizedClassName = stripBootInfPrefix(className);
            if (isApiClass(classBytes)) {
                try {
                    ClassReader reader = new ClassReader(classBytes);
                    ClassNode classNode = new ClassNode();
                    reader.accept(classNode, 0);
                    
                    Map<String, String> apiMethods = new HashMap<>();
                    for (MethodNode method : classNode.methods) {
                        String methodDesc = method.name + method.desc;
                        if (method.visibleAnnotations != null) {
                            for (AnnotationNode annotation : method.visibleAnnotations) {
                                if (annotation.desc.contains("Mapping")) {
                                    apiMethods.put(methodDesc, normalizedClassName + "." + method.name);
                                    break;
                                }
                            }
                        }
                    }
                    if (!apiMethods.isEmpty()) {
                        apiMethodsMap.put(className, apiMethods);
                    }
                } catch (Exception e) {
                    log.error("分析API方法失败: " + className, e);
                }
            }
        });

        log.info("找到的API类和方法: {}", apiMethodsMap);

        // 遍历所有变更的类
        differences.values().forEach(diff -> {
            // 获取依赖这个类的所有方法
            Set<String> dependentMethods = diff.getDependentMethods();
            
            // 检查依赖方法中是否有API方法
            dependentMethods.forEach(dependentMethod -> {
                String dependentClassName = dependentMethod.substring(0, dependentMethod.lastIndexOf('.'));
                String methodDesc = dependentMethod.substring(dependentMethod.lastIndexOf('.') + 1);
                
                // 尝试两种形式的类名
                Map<String, String> apiMethods = apiMethodsMap.get(dependentClassName);
                if (apiMethods == null) {
                    apiMethods = apiMethodsMap.get(normalizeClassName(dependentClassName));
                }
                
                if (apiMethods != null && apiMethods.containsKey(methodDesc)) {
                    String apiMethodName = apiMethods.get(methodDesc);
                    diff.addDependentApiMethod(apiMethodName);
                    log.info("发现API依赖: {} -> {}", apiMethodName, diff.getClassName());
                }
            });
        });
    }

    private boolean isApiClass(byte[] classBytes) {
        try {
            ClassReader reader = new ClassReader(classBytes);
            ClassNode classNode = new ClassNode();
            reader.accept(classNode, 0);
            
            // 检查类上的注解
            if (classNode.visibleAnnotations != null) {
                for (AnnotationNode annotation : classNode.visibleAnnotations) {
                    if (CONTROLLER_DESC.equals(annotation.desc) || 
                        REST_CONTROLLER_DESC.equals(annotation.desc)) {
                        return true;
                    }
                }
            }

            // 检查类中的方法是否有 Mapping 注解
            if (classNode.methods != null) {
                for (MethodNode method : classNode.methods) {
                    if (method.visibleAnnotations != null) {
                        for (AnnotationNode annotation : method.visibleAnnotations) {
                            if (annotation.desc.contains("Mapping")) {
                                return true;
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("检查API类失败", e);
        }
        return false;
    }

    private void extractClassNamesFromDesc(String desc, Set<String> dependencies) {
        // 提取方法描述符中的类名
        int start = desc.indexOf('L');
        while (start != -1) {
            int end = desc.indexOf(';', start);
            if (end != -1) {
                String className = desc.substring(start + 1, end).replace('/', '.');
                dependencies.add(className);
                start = desc.indexOf('L', end);
            } else {
                break;
            }
        }
    }
}
